/*
 * @Author: 李石
 * @Date: 2024-05-20 08:56:00
 * @LastEditors: lishi
 * @LastEditTime: 2024-05-24 14:10:37
 * @Description: 
 * Copyright (c) 2024 by ${lishi0105@163.com}, All Rights Reserved. 
 */
#include "logger.hpp"
#include "StreamService.hpp"

StreamService::StreamService() :
    sys_params(SysParams::getInstance())
{
    m_threadPool = std::make_shared<ThreadPool>(3);
}

StreamService::~StreamService()
{
    sys_params = nullptr;
}

void StreamService::init()
{
    std::thread init_tid(&StreamService::initProxyThread, this);
    init_tid.detach();
}

void StreamService::initProxyThread()
{
    std::lock_guard<std::mutex> lock(m_stream_mtx);
    std::string err;
    auto stream_list = sys_params->get_stream(err);
    if(stream_list == nullptr){
        LOGI("no stream in config");
        return;
    }
    for(auto &stream : stream_list->streams){
        auto key = stream->app + ":" + stream->stream;
        try{
            if(proxyer_map.find(key) != proxyer_map.end()){
                LOGE("program bug stream proxyer not found in config but already exists");
                proxyer_map.erase(key);
            }
            auto proxyer = StreamProxyer::CreateShared(stream->app, stream->stream, stream->url, stream->rtp_type);
            if(proxyer == nullptr){
                LOGE("create stream proxyer failed");
                continue;
            }
            proxyer_map[key] = proxyer;
        }catch(std::exception &e){
            LOGE("StreamProxyer::CreateShared {} {} exception: {}",stream->app, stream->stream, e.what());
        }
    }
}

StreamReportDto::Ptr 
StreamService::insertStream(const StreamAddDto::Ptr add_dto, std::string &err) 
{
    std::lock_guard<std::mutex> lock(m_stream_mtx);
    err = "success";
    if(sys_params == nullptr) {
        err = "sys_params is nullptr";
        LOGE(err);
        return nullptr;
    }
    if(add_dto == nullptr){
        err = "add_dto is nullptr";
        LOGE(err);
        return nullptr;
    }
    if(!sys_params->insert_stream(add_dto->app, add_dto->stream, add_dto->url, add_dto->rtp_type, err)){
        LOGE(err);
        return nullptr;
    }
    std::string key = add_dto->app + ":" + add_dto->stream;
    if(proxyer_map.find(key) != proxyer_map.end()){
        err = "program bug stream proxyer not found in config but already exists";
        LOGE(err);
        proxyer_map.erase(key);
        return nullptr;
    }
    try{
        auto proxyer = StreamProxyer::CreateShared(add_dto->app, add_dto->stream, add_dto->url, add_dto->rtp_type);
        if(proxyer == nullptr){
            err = "create stream proxyer failed";
            LOGE(err);
            return nullptr;
        }
        proxyer_map[key] = proxyer;
    }catch(std::exception &e){
        LOGE("StreamProxyer::CreateShared {} {} exception: {}",add_dto->app, add_dto->stream, e.what());
        return nullptr;
    }
    sys_params->save();
    return sys_params->get_stream(add_dto->app, add_dto->stream, err);
}

bool StreamService::removeStream(const StreamIDDto::Ptr dto, std::string &err)
{
    std::lock_guard<std::mutex> lock(m_stream_mtx);
    err = "success";
    if(sys_params == nullptr) {
        err = "sys_params is nullptr";
        LOGE(err);
        return false;
    }
    if(dto == nullptr){
        err = "dto is nullptr";
        LOGE(err);
        return false;
    }
    if(!sys_params->remove_stream(dto->app, dto->stream, err)){
        LOGE(err);
        return false;
    }
    sys_params->save();
    m_threadPool->enqueue([this, dto]{
        auto key = dto->app + ":" + dto->stream;
        auto itor = proxyer_map.find(key);
        if(itor != proxyer_map.end()){
            proxyer_map.erase(itor);
        }
    });
    return true;
}

StreamReportDto::Ptr 
StreamService::getStream(const StreamIDDto::Ptr dto, std::string &err) const
{
    std::lock_guard<std::mutex> lock(m_stream_mtx);
    err = "success";
    if(sys_params == nullptr) {
        err = "sys_params is nullptr";
        LOGE(err);
        return nullptr;
    }
    if(dto == nullptr){
        err = "dto is nullptr";
        LOGE(err);
        return nullptr;
    }
    auto report = sys_params->get_stream(dto->app, dto->stream, err);
    if(report == nullptr)return nullptr;
    std::string key = dto->app + ":" + dto->stream;
    auto itor = proxyer_map.find(key);
    if(itor == proxyer_map.end()){
        err = std::string("program bug stream proxyer[") + key + std::string("] not found");
        LOGE(err);
        return nullptr;
    }
    report->codec_id = itor->second->codec_id();
    report->alive = itor->second->alive();
    report->play = itor->second->playUrl();
    return report;
}

StreamListDto::Ptr StreamService::getStream(std::string &err) const
{
    std::lock_guard<std::mutex> lock(m_stream_mtx);
    err = "success";
    if(sys_params == nullptr) {
        err = "sys_params is nullptr";
        LOGE(err);
        return nullptr;
    }
    auto lists = sys_params->get_stream(err);
    if(lists == nullptr){
        LOGE(err);
        return nullptr;
    }
    for(auto &stream : lists->streams){
        std::string key = stream->app + ":" + stream->stream;
        auto itor = proxyer_map.find(key);
        if(itor == proxyer_map.end()){
            err = "program bug stream proxyer not found";
            LOGE(err);
            continue;
        }
        stream->codec_id = itor->second->codec_id();
        stream->alive = itor->second->alive();
        stream->play = itor->second->playUrl();
    }
    return lists;
}

// Path: src/httpService/StreamService.cpp